/* 
* Copyright 2010 Johannes Tuikkala <johannes.tuikkala@itmill.com>
* 
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.vaadin.webcamforvaadin.gwt.flex {
	import com.adobe.images.JPGEncoder;
	import flash.geom.Matrix;
	
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.external.ExternalInterface;
	import flash.geom.Rectangle;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	import flash.system.*;
	import flash.utils.ByteArray;
	import flash.utils.Timer;
	
	import mx.controls.Alert;
	import mx.core.UIComponent;
	
	public class WebCamForVaadin extends UIComponent {
		private const JSESSIONID_PARAM:String = "jsessioid";
		private const POSTACTION_PARAM:String = "postaction";
		private const BASEURL_PARAM:String = "baseurl";
		private const CAM_WIDTH:String = "webcamWidth";
		private const CAM_HEIGHT:String = "webcamHeight";
		
		private var jpg:JPGEncoder = new JPGEncoder();
		private var bitmapData:BitmapData;
		private var video:Video;		
		private var _pid:String;
		private var cam:Camera;
		private var postAction:String;
		private var jsessionId:String;
		private var captureButton:Loader;
		
		private var lastWidth:uint = 640;
		private var lastHeight:uint = 480;
		
		/**
		 * Constructor
		 */
		public function WebCamForVaadin():void {			
			super();
			cam = Camera.getCamera();
			video = new Video(lastWidth,lastHeight);
			if (cam==null) {
				errorMessage("Sorry, no web camera found!");
			} else {
				cam.setQuality(0, 100);
				cam.setMode(lastWidth, lastHeight, 30, false);
				video.attachCamera(cam);
			}
			captureButton = new Loader();
			captureButton.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			captureButton.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			captureButton.x = 150;
			captureButton.x = 5;
			addChild(captureButton);

			video.x = 2;
			video.y = 28;
			addChild(video);
			bitmapData = new BitmapData(video.width,video.height);
		}
		
		private function mouseDownHandler(event:MouseEvent):void {
		}
		private function mouseUpHandler(event:MouseEvent):void {
			capturePicNow();
		}
				
		/**
		 * This function is called when the flash has finished loading. This
		 * function will intialize the communication interface between flash
		 * and GWT. 
		 */
		private function init():void {
			// Are we even able to initialize a external communication interface?
			if (ExternalInterface.available) {
				ExternalInterface.addCallback("captureNow", this.capturePicNow);
				ExternalInterface.addCallback("setParameter", this.setParameter);
				
				try {
					ExternalInterface.call("vaadin.webcamforvaadin['setCapturedImage_" + _pid + "']",null);
				} catch (error:Error) {
					Alert.show("An Error occurred: " + error.message + "\n");
				}
			} else {
				errorMessage("No external interface\n");
			}	
		}
		
		private function setId(id:String):void {			
			_pid = id.toString();
		}
		
		private function capturePicNow():void {
			try {			
				if (cam==null) {
					errorMessage("Sorry, no web camera found!");
					return;
				}
				var rect:Rectangle = new Rectangle(video.x,video.y,video.width,video.height);
				bitmapData.draw(video, new Matrix(), null, null, rect);
				streamByteArrayThroughPost(jpg.encode(bitmapData));
			} catch (error:Error) {
				Alert.show("An Error occurred: " + error.message + "\n");
			}
		}

		
		private function errorMessage(msg:String):void {
			ExternalInterface.call("vaadin.webcamforvaadin['setErrorMessage_" + _pid + "']",msg);
		}
		
		/**
		 * send image within upload-post request
		 * DEPRECATED
		 */
		private function streamStringThroughPost(imageData:String):void {
			var loader:URLLoader = new URLLoader();  
			var request:URLRequest = new URLRequest(postAction+";jsesionid="+jsessionId);  
			var boundary:String = "****MULTIPART"+(new Date().getMilliseconds());
			
			request.method = URLRequestMethod.POST;
			request.contentType = "multipart/form-data;boundary="+boundary;
			var content:String = "--"+boundary+"\r\nContent-Disposition: form-data; name=\"PID_SWEBCAM_UPLOAD_PID\"; filename=\"webcamimagedata.txt\"\r\n\r\n"+imageData+"\r\n--"+boundary+"--\r\n";
			request.data = content;

			loader.load(request); 
		}
		
		/**
		 * Stream bytearray trough post
		 */
		private function streamByteArrayThroughPost(imageData:ByteArray):void {
			var loader:URLLoader = new URLLoader();  
			var request:URLRequest = new URLRequest(postAction+";jsesionid="+jsessionId);  
			var boundary:String = "****MULTIPART"+(new Date().getMilliseconds());
			
			request.method = URLRequestMethod.POST;
			request.contentType = "multipart/form-data;boundary="+boundary;
			var contentStart:String = "--"+boundary+"\r\nContent-Disposition: form-data; name=\"PID_SWEBCAM_UPLOAD_PID\"; filename=\"webcamimagedata.jpg\"\r\n\r\n"
			var contentEnd:String = "\r\n--"+boundary+"--\r\n";
			var contentData:ByteArray = new ByteArray();
			contentData.writeMultiByte(contentStart,"utf-8");
			contentData.writeBytes(imageData);
			contentData.writeMultiByte(contentEnd,"utf-8");
			request.data = contentData;
			loader.load(request); 
		}
		
		private function setParameter(name:String, value:String):void {
			if (name == JSESSIONID_PARAM) {
				jsessionId = value;
			} else if (name == POSTACTION_PARAM) {
				postAction = value;
			} else if (name == BASEURL_PARAM) {
				captureButton.load(new URLRequest(value + "camera.png"));
			} else if (name == CAM_WIDTH) {
				lastWidth = int(value);
				video.attachCamera(null);
				removeChild(video);
				cam.setMode(lastWidth, lastHeight, 30, false);
				video = new Video(lastWidth,lastHeight);
				video.attachCamera(cam);
				video.x = 2;
				video.y = 28;
				addChild(video);
				bitmapData = new BitmapData(lastWidth,lastHeight);
			} else if (name == CAM_HEIGHT) {
				lastHeight = int(value);
				video.attachCamera(null);
				removeChild(video);
				cam.setMode(lastWidth, lastHeight, 30, false);
				video = new Video(lastWidth,lastHeight);
				video.attachCamera(cam);
				video.x = 2;
				video.y = 28;
				addChild(video);
				bitmapData = new BitmapData(lastWidth,lastHeight);
			}
		}
		
		/**
		 * Sets the unique identifier of this widget. This is used to create
		 * the dynamic function names in the external interface calls.
		 * @param String p
		 */
		public function set pid(p:String):void {
			if(this._pid == null) {
				this._pid = p;
				init();	
			}	
		}
	}
	
}